/**
  ******************************************************************************
  * @file    uart_handler.c
  * @author  woshiashuai
  * @version V2.1
  * @date    2023-09-26
  * @brief   串口管理
  *          (使用帧间隔分帧或现有的分帧方法)
  *
  ******************************************************************************
  * @attention
  *
  * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
  * 出处链接:https://gitee.com/woshiashuai/mcu_development_module.git
  *
  ******************************************************************************
  */

/* 包含头文件-----------------------------------------------------------------*/
#include "uart_handler.h"

/**
 * @addtogroup modules
 * @{
 */

/**
 * @defgroup uart_handler uart_handler
 * @{
 */

/* 私有宏定义-----------------------------------------------------------------*/
/**
 * @defgroup uart_handler_local_macros uart handler local macros
 * @{
 */

/**
 * @defgroup uart_handler_check_parameters_validity uart handler check parameters validity
 * @{
 */
/* 串口管理序号有效性检查 */
#define IS_VALID_CH(x)                                                        \
(       ((x) == 0)                     ||                                     \
        ((x) > 0)                      &&                                     \
        ((x) < UART_HANDLER_NUM))
/**
 * @}
 */

/**
 * @}
 */

/* 私有类型定义---------------------------------------------------------------*/

/* 私有变量-------------------------------------------------------------------*/
/**
 * @defgroup uart_handler_local_variables uart handler local variables
 * @{
 */

static uart_handler_t uartHandlerArr[UART_HANDLER_NUM]; /*!< 串口管理数组 */

/**
 * @}
 */

/* 全局变量-------------------------------------------------------------------*/

/* 私有函数原型---------------------------------------------------------------*/

/**
 * @defgroup uart_handler_global_functions uart handler global functions
 * @{
 */

/**
  * @brief  串口管理初始化
  *
  * @param  ch      : 串口管理序号(即数组索引)
  *
  * @param  txBuf   : 串口发送缓冲区
  *
  * @param  txLen   : 串口发送缓冲区大小
  *
  * @param  rxBuf   : 串口接收缓冲区
  *
  * @param  rxLen   : 串口接收缓冲区大小
  *
  * @param  txEnFn  : 串口发送前准备函数
  *
  * @param  baud    : 串口波特率(内部转换为帧间隔超时时间,填0则帧间隔超时时间为0)
  *
  * @param  timeout : 接收超时时间ms(无需求可忽略)
  *
  * @retval None
  */
void uart_hr_init(uint8_t ch, void *txBuf, uint32_t txLen, void *rxBuf, uint32_t rxLen, uart_tx_en_fn_t txEnFn, uint32_t baud, uint16_t timeout)
{
    ASSERT_PARAM(IS_VALID_CH(ch));
    ASSERT_PARAM(IS_VALID_POINT(txBuf));
    ASSERT_PARAM(IS_VALID_POINT(rxBuf));
    ASSERT_PARAM(IS_VALID_POINT(txEnFn));
    
    ring_queue_init(&uartHandlerArr[ch].txRingQueue, txBuf, txLen);
    ring_queue_init(&uartHandlerArr[ch].rxRingQueue, rxBuf, rxLen);
    uartHandlerArr[ch].uartTxEnFn = txEnFn;
    uart_hr_set_frame_intv(ch, baud);
    uartHandlerArr[ch].recTimeout = timeout;
}

/**
  * @brief  串口管理轮询处理(1ms)
  *
  * @param  ch          : 串口管理序号(即数组索引)
  *
  * @retval uint8_t
  *    @arg RET_OK      : 接收完成
  *    @arg RET_ERR     : 接收未完成
  *    @arg RET_TIMEOUT : 接收超时(无需求可忽略)
  */
uint8_t uart_hr_poll(uint8_t ch)
{
    ASSERT_PARAM(IS_VALID_CH(ch));
    
    /* 帧间隔判断 */
    if(uartHandlerArr[ch].curFrameIntv && uartHandlerArr[ch].curFrameIntv++ > uartHandlerArr[ch].targetFrameIntv)
    {
        uartHandlerArr[ch].curFrameIntv = 0;
        uartHandlerArr[ch].recTimeoutCnt = 0;
        
        return RET_OK;
    }
    /* 接收超时判断 */
    if(uartHandlerArr[ch].recTimeoutCnt && uartHandlerArr[ch].recTimeoutCnt++ > uartHandlerArr[ch].recTimeout)
    {
        uartHandlerArr[ch].recTimeoutCnt = 0;
        
        return RET_TIMEOUT;
    }
    
    return RET_ERR;
}

/**
  * @brief  读出数据从串口接收缓冲区
  *
  * @param  ch   : 串口管理序号(即数组索引)
  *
  * @param  pBuf : 数据存储区
  *
  * @param  len  : 读出长度byte
  *
  * @retval 实际读出的长度
  */
uint32_t uart_hr_read_rx_buf(uint8_t ch, void *pBuf, uint32_t len)
{
    ASSERT_PARAM(IS_VALID_CH(ch));
    ASSERT_PARAM(IS_VALID_POINT(pBuf));
    
    len = (len > ring_queue_can_read(&uartHandlerArr[ch].rxRingQueue)) ? ring_queue_can_read(&uartHandlerArr[ch].rxRingQueue) : len;
    if(0 < len)
    {
        ring_queue_read(&uartHandlerArr[ch].rxRingQueue, pBuf, len);
    }
    
    return len;
}

/**
  * @brief  写入数据到串口接收缓冲区
  *
  * @note   一般加入到串口接收中断
  *
  * @param  ch   : 串口管理序号(即数组索引)
  *
  * @param  pBuf : 数据缓存区
  *
  * @param  len  : 写入长度byte
  *
  * @retval 实际写入的长度
  */
uint32_t uart_hr_write_rx_buf(uint8_t ch, void *pBuf, uint32_t len)
{
    ASSERT_PARAM(IS_VALID_CH(ch));
    ASSERT_PARAM(IS_VALID_POINT(pBuf));
    
    len = (len > ring_queue_can_write(&uartHandlerArr[ch].rxRingQueue)) ? ring_queue_can_write(&uartHandlerArr[ch].rxRingQueue) : len;
    if(0 < len)
    {
        ring_queue_write(&uartHandlerArr[ch].rxRingQueue, pBuf, len);
        uartHandlerArr[ch].curFrameIntv = 1;
    }
    
    return len;
}

/**
  * @brief  读出数据从串口发送缓冲区
  *
  * @note   一般加入到串口发送中断
  *
  * @param  ch   : 串口管理序号(即数组索引)
  *
  * @param  pBuf : 数据存储区
  *
  * @param  len  : 读出长度byte
  *
  * @retval 实际读出的长度
  */
uint32_t uart_hr_read_tx_buf(uint8_t ch, void *pBuf, uint32_t len)
{
    ASSERT_PARAM(IS_VALID_CH(ch));
    ASSERT_PARAM(IS_VALID_POINT(pBuf));
    
    len = (len > ring_queue_can_read(&uartHandlerArr[ch].txRingQueue)) ? ring_queue_can_read(&uartHandlerArr[ch].txRingQueue) : len;
    if(0 < len)
    {
        ring_queue_read(&uartHandlerArr[ch].txRingQueue, pBuf, len);
    }
    else
    {
        uartHandlerArr[ch].uartTxEnFn(0);
        uartHandlerArr[ch].recTimeoutCnt = 1;
    }
    
    return len;
}

/**
  * @brief  写入数据到串口发送缓冲区
  *
  * @param  ch   : 串口管理序号(即数组索引)
  *
  * @param  pBuf : 数据缓存区
  *
  * @param  len  : 写入长度byte
  *
  * @retval 实际写入的长度
  */
uint32_t uart_hr_write_tx_buf(uint8_t ch, void *pBuf, uint32_t len)
{
    ASSERT_PARAM(IS_VALID_CH(ch));
    ASSERT_PARAM(IS_VALID_POINT(pBuf));
    
    len = (len > ring_queue_can_write(&uartHandlerArr[ch].txRingQueue)) ? ring_queue_can_write(&uartHandlerArr[ch].txRingQueue) : len;
    if(0 < len)
    {
        ring_queue_write(&uartHandlerArr[ch].txRingQueue, pBuf, len);
        uartHandlerArr[ch].uartTxEnFn(1);
    }
    
    return len;
}

/**
  * @brief  设置串口管理帧间隔超时时间
  *
  * @param  ch   : 串口管理序号(即数组索引)
  *
  * @param  baud : 波特率(内部转换为帧间隔超时时间,填0则帧间隔超时时间为0)
  *
  * @retval None
  */
void uart_hr_set_frame_intv(uint8_t ch, uint32_t baud)
{
    if(9600 < baud)
    {
        uartHandlerArr[ch].targetFrameIntv = 3;
    }
    else if(0 == baud)
    {
        uartHandlerArr[ch].targetFrameIntv = 0;
    }
    else
    {
        uartHandlerArr[ch].targetFrameIntv = 10000 / baud * 3.5;
    }
}

/**
  * @brief  获取串口管理帧间隔超时时间
  *
  * @param  ch : 串口管理序号(即数组索引)
  *
  * @retval 帧间隔超时时间ms
  */
uint16_t uart_hr_get_frame_intv(uint8_t ch)
{
    return uartHandlerArr[ch].targetFrameIntv;
}

/**
  * @brief  设置串口管理接收超时时间
  *
  * @param  ch      : 串口管理序号(即数组索引)
  *
  * @param  timeout : 接收超时时间
  *
  * @retval None
  */
void uart_hr_set_rec_timeout(uint8_t ch, uint16_t timeout)
{
    uartHandlerArr[ch].recTimeout = timeout;
}

/**
  * @brief  获取串口管理接收超时时间
  *
  * @param  ch : 串口管理序号(即数组索引)
  *
  * @retval 串口管理接收超时时间
  */
uint16_t uart_hr_get_rec_timeout(uint8_t ch)
{
    return uartHandlerArr[ch].recTimeout;
}

/**
 * @}
 */

/**
 * @}
 */

/**
 * @}
 */
